package com.qinsilk.axon.inventory.command

import java.util.*
import org.axonframework.commandhandling.CommandHandler
import org.axonframework.eventsourcing.EventSourcingHandler
import org.axonframework.modelling.command.AggregateIdentifier
import org.axonframework.modelling.command.AggregateLifecycle
import org.axonframework.spring.stereotype.Aggregate

@Aggregate
class InventoryAggregate {

    @AggregateIdentifier private var inventoryId: String? = null
    private var productName: String? = null
    private var quantity: Int = 0
    private val eventHistory: MutableMap<String, Any> = HashMap()

    constructor()

    @CommandHandler
    constructor(command: CreateInventoryCommand) {
        AggregateLifecycle.apply(
                InventoryCreatedEvent(
                        command.inventoryId,
                        command.productName,
                        command.initialQuantity
                )
        )
    }

    @EventSourcingHandler
    fun on(event: InventoryCreatedEvent) {
        this.inventoryId = event.inventoryId
        this.productName = event.productName
        this.quantity = event.initialQuantity
        // 初始化eventHistory
        // 注意：在事件溯源中，我们不应该在事件处理方法中初始化集合
    }

    @CommandHandler
    fun handle(command: StockInCommand) {
        val eventId = UUID.randomUUID().toString()
        AggregateLifecycle.apply(
                StockInRecordedEvent(command.inventoryId, command.quantity, command.reason, eventId)
        )
    }

    @EventSourcingHandler
    fun on(event: StockInRecordedEvent) {
        this.quantity += event.quantity
        // 记录事件到历史中，便于后续撤销
        this.eventHistory[event.eventId] = event
    }

    @CommandHandler
    fun handle(command: StockOutCommand) {
        if (this.quantity < command.quantity) {
            throw IllegalStateException("库存不足，无法出库")
        }

        val eventId = UUID.randomUUID().toString()
        AggregateLifecycle.apply(
                StockOutRecordedEvent(
                        command.inventoryId,
                        command.quantity,
                        command.reason,
                        eventId
                )
        )
    }

    @EventSourcingHandler
    fun on(event: StockOutRecordedEvent) {
        this.quantity -= event.quantity
        // 记录事件到历史中，便于后续撤销
        this.eventHistory[event.eventId] = event
    }

    @CommandHandler
    fun handle(command: CancelOperationCommand) {
        // 检查事件是否存在
        if (!this.eventHistory.containsKey(command.eventId)) {
            throw IllegalStateException("找不到指定的事件记录: ${command.eventId}")
        }

        val event = this.eventHistory[command.eventId]!!

        val eventType = event.javaClass.simpleName
        val quantity =
                when (event) {
                    is StockInRecordedEvent -> event.quantity
                    is StockOutRecordedEvent -> event.quantity
                    else -> throw IllegalStateException("不支持撤销的事件类型: $eventType")
                }

        AggregateLifecycle.apply(
                OperationCancelledEvent(command.inventoryId, command.eventId, eventType, quantity)
        )
    }

    @EventSourcingHandler
    fun on(event: OperationCancelledEvent) {
        // 根据事件类型执行相反的操作
        when (event.eventType) {
            "StockInRecordedEvent" -> {
                // 撤销入库操作，减少相应数量
                this.quantity -= event.quantity
            }
            "StockOutRecordedEvent" -> {
                // 撤销出库操作，增加相应数量
                this.quantity += event.quantity
            }
        }

        // 从历史记录中移除已撤销的事件
        this.eventHistory.remove(event.eventId)
    }

    fun getInventoryId(): String? = inventoryId

    fun getProductName(): String? = productName

    fun getQuantity(): Int = quantity
}
